%include "boot.inc"

[bits 16]
section Loader vstart=LOADER_BASE_ADDR
START:
    mov ax,cs
    mov ds,ax
    mov ss,ax

    ;master PIC
    mov al,00010001b;ICW1
    out 20h,al
    mov al,20h;ICW2
    out 21h,al
    mov al,00000100b;ICW3
    out 21h,al
    mov al,00000001b;ICW4
    out 21h,al
    ;slave PIC
    mov al,00010001b;ICW1
    out 0a0h,al
    mov al,28h;ICW2
    out 0a1h,al
    mov al,2;ICW3
    out 0a1h,al
    mov al,00000001b;ICW4
    out 0a1h,al

    mov al,11111000b;master OCW1
    out 21h,al
    mov al,11101110b;slave OCW1
    out 0a1h,al

    ;xor ah,ah
    ;mov al,13h
    ;int 10h;320 * 200 256 colors graphics mode

    in al,92h
    or al,00000010b
    out 92h,al;open A20 mode
    lgdt [gdt_ptr]
    mov eax,[idt_start]
    mov edx,[idt_start+4]
    mov bx,idt_start+8
    mov cx,0x80
    .init_loop:
        mov [bx],eax
        mov [bx+4],edx
        add bx,8
        loop .init_loop
    mov word [idt_start],int_0x00
    mov word [idt_start+08h],int_0x01
    mov word [idt_start+10h],int_0x02
    mov word [idt_start+18h],int_0x03
    mov word [idt_start+100h],int_0x20
    mov word [idt_start+108h],int_0x21
    mov word [idt_start+140h],int_0x28
    mov word [idt_start+160h],int_0x2C
    mov word [idt_start+170h],int_0x2E
    lidt [idt_ptr]
    mov eax,cr0
    or eax,1
    mov cr0,eax
    jmp word 0x0008:protected_mode

[bits 32]
protected_mode:
    mov ax,0x0010
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov esp,0x80000
    mov ebp,esp
    mov ax,0x0018
    mov gs,ax
    mov dword [0x500],getchar
    mov dword [0x504],gdt_ptr
    mov dword [0x508],idt_ptr
    mov dword [0x50C],0
    call readdisk_m32
    ;载入PE程序
    mov ebx,COFF_BASE_ADDR
    cmp word [ebx],0x5a4d
    jnz Error
    mov eax,[ebx+60]
    add ebx,eax
    cmp dword [ebx],0x00004550
    jnz Error
    cmp word [ebx+20],0xE0
    jnz Error
    push dword [ebx+40]
    mov edx,[ebx+52]
    xor ecx,ecx
    mov cx,[ebx+6]
    jcxz Error
    add ebx,0xF8
    xor esi,esi
    .load_seg:
        push ecx
        mov edi,[ebx+12]
        mov ecx,[ebx+16]
        mov esi,[ebx+20]
        add esi,COFF_BASE_ADDR
        shr ecx,2
        add edi,edx
        rep movsd
        pop ecx
        add ebx,40
        loop .load_seg
    pop eax
    add eax,edx
    mov esp,edx
    mov ebp,esp
    finit ;要用浮点数运算就加上去
    call eax
    mov eax,cr0
    and al,0xfe
    mov cr0,eax
    jmp dword 0xffff:0
Error:
    not byte [gs:0x01]
    hlt
    jmp Error
int_0x20:
    pushad
    ;not byte [gs:0x07]
    mov eax,[0x50C]
    test eax,eax
    jz .L1
    call eax
    .L1:
    mov al,0x20
    out 0x20,al
    popad
    iret
int_0x21:
    pushad
    in al,0x60
    mov [getchar.ch],al
    mov al,0x20
    out 0x20,al
    popad
    iret
int_0x2C:
    not byte [0xB8001]
    pushad
    in al,0x60
    mov al,0x20
    out 0x20,al
    out 0xA0,al
    popad
    iret
readdisk_m32:
    mov dx,0x1f2
    mov al,COFF_SECTOR_NUMBER
    out dx,al
    mov eax,COFF_START_SECTOR
    mov dx,0x1f3
    out dx,al
    mov dx,0x1f4
    mov cl,8
    shr eax,cl
    out dx,al
    mov dx,0x1f5
    shr eax,cl
    out dx,al
    mov dx,0x1f6
    shr eax,cl
    and al,0xf
    or al,0xe0
    out dx,al
    mov dx,0x1f7
    mov al,0x20
    out dx,al
    .wait_loop:
        nop
        in al,dx
        and al,0x88
        cmp al,0x8
        jnz .wait_loop
    mov ax,ds
    mov es,ax
    mov ecx,COFF_SECTOR_NUMBER * 0x80
    mov edi,COFF_BASE_ADDR
    mov dx,0x1f0
    rep insd
    ret
getchar:
    xor al,al
    cmp byte [.ch],0
    jz .L0
    xchg al,[.ch]
    ret
    .L0:
    hlt
    xchg al,[.ch]
    test al,al
    jz .L0
    ret
    .ch:db 0
int_all:
    pushad
    push ds
    push es
    push fs
    push gs
    xor eax,eax
    mov al,[.irq]
    not byte [eax*2+0xb8a01]
    pop gs
    pop fs
    pop es
    pop ds
    popad
    iret
    .irq:db 0
int_0x00:
    mov byte [int_all.irq],00h
    jmp int_all
int_0x01:
    mov byte [int_all.irq],01h
    jmp int_all
int_0x02:
    mov byte [int_all.irq],02h
    jmp int_all
int_0x03:
    mov byte [int_all.irq],03h
    jmp int_all
int_0x28:
    mov byte [int_all.irq],28h
    jmp int_all
int_0x2E:
    mov byte [int_all.irq],2Eh
    jmp int_all

gdt_ptr:
    dw gdt_end - gdt_start - 1
    dd gdt_start
gdt_start:
    dd 0
    dd 0
    dd (0x0000 << 16) | 0x1000
    dd (0x00 << 24) | DESC_G_4K | DESC_D_32 | DESC_P | (0x0 << 16) | DESC_DPL_0 | DESC_TYPE_CODE | DESC_CODE_READABLE | 0x00
    dd (0x0000 << 16) | 0x1000
    dd (0x00 << 24) | DESC_G_4K | DESC_D_32 | DESC_P | (0x0 << 16) | DESC_DPL_0 | DESC_TYPE_DATA | DESC_DATA_WRITABLE | 0x00
    dd (0x8000 << 16) | 0x1040
    dd (0x00 << 24) | DESC_D_32 | DESC_P | (0x0 << 16) | DESC_DPL_0 | DESC_TYPE_DATA | DESC_DATA_WRITABLE | 0x0B
gdt_end:

idt_ptr:
    dw idt_end - idt_start - 1
    dd idt_start
idt_start:
    dw int_all
    dw 0x0008
    dd (0x0000 << 16) | DESC_P | DESC_DPL_0 | INTR_TYPE_INT32
    times 0x400 db 0
idt_end:
;intr_name[0] = "#DE Divide Error";
;intr_name[1] = "#DB Debug Exception";
;intr_name[2] = "NMI Interrupt";
;intr_name[3] = "#BP Breakpoint Exception";
;intr_name[4] = "#OF Overflow Exception";
;intr_name[5] = "#BR BOUND Range Exceeded Exception";
;intr_name[6] = "#UD Invalid Opcode Exception";
;intr_name[7] = "#NM Device Not Available Exception";
;intr_name[8] = "#DF Double Fault Exception";
;intr_name[9] = "Coprocessor Segment Overrun";
;intr_name[10] = "#TS Invalid TSS Exception";
;intr_name[11] = "#NP Segment Not Present";
;intr_name[12] = "#SS Stack Fault Exception";
;intr_name[13] = "#GP General Protection Exception";
;intr_name[14] = "#PF Page-Fault Exception";
;// intr_name[15] reserved.
;intr_name[16] = "#MF x87 FPU Floating-Point Error";
;intr_name[17] = "#AC Alignment Check Exception";
;intr_name[18] = "#MC Machine-Check Exception";
;intr_name[19] = "#XF SIMD Floating-Point Exception";